package com.dj.ms.resolver;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dj.common.annotation.QueryRequestBody;
import com.dj.common.support.HttpRequestWrapper;
import com.dj.ms.session.PrincipalHandler;
import com.dj.ms.session.Principal;
import com.dj.ms.session.SessionCollector;
import com.dj.ms.support.SpringBeanFactoryUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <br>
 * <p>client params 解析器</p>
 *
 * <br>
 *
 * @author ZJG
 * @version 1.0
 * @date 2021/8/4 下午2:26
 */
@Slf4j
@Component
@Order(Ordered.LOWEST_PRECEDENCE - 1)
public class CurrentUserMethodResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private SessionCollector sessionCollector;

    private static final AtomicBoolean hasQueryRequest = new AtomicBoolean(false);

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        hasQueryRequest.set(parameter.hasParameterAnnotation(QueryRequestBody.class));
        if (Principal.class.isAssignableFrom(parameter.getParameterType())
                || hasQueryRequest.get()) {
            return true;
        }
        return false;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        if (ObjectUtil.isNull(this.sessionCollector)) {
            this.sessionCollector = SpringBeanFactoryUtils.getBean("sessionCollector");
        }
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            if (hasQueryRequest.get()) {
                return processQueryRequest(parameter, webRequest);
            }
            String s = PrincipalHandler.parseUserCode(request);
            if (StringUtils.isBlank(s)) {
                return null;
            }
            if (ObjectUtil.isNotNull(this.sessionCollector)) {
                Object o = this.sessionCollector.get();
                if (ObjectUtils.isNotEmpty(o)) {
                    Map<String, Object> o1 = (Map<String, Object>) o;
                    Principal principal = o1.containsKey(s) ? (Principal) o1.get(s) : null;
                    String bu = URLUtil.decode(request.getHeader("bu"), "UTF-8");
                    String sc = URLUtil.decode(request.getHeader("sc"), "UTF-8");
                    String clientSource = URLUtil.decode(request.getHeader("clientSource"), "UTF-8");
                    principal.setBizUnit(bu);
                    principal.setDomainChannel(sc);
                    principal.setClientSource(clientSource);
                    log.info("principal对象:{}", JSON.toJSONString(principal));
                    return principal;
                }
            }
        }
        return null;
    }

    private Object processQueryRequest(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) {
        String name = methodParameter.getParameterAnnotation(QueryRequestBody.class).value();
        HttpServletRequest httpServletRequest = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
        HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpServletRequest);

        Map<String, String[]> map = httpServletRequest.getParameterMap();
        String parameterJsonStr = requestWrapper.getBody();
        Class clazz = methodParameter.getParameterType();
        if (Collection.class.isAssignableFrom(clazz)) {
            if (CollectionUtil.isEmpty(map)
                    && StrUtil.isNotBlank(parameterJsonStr)
                    && JSONUtil.isJsonObj(parameterJsonStr)) {
                return JSONUtil.toBean(parameterJsonStr, clazz);
            }
            // 集合泛型
            Type genericType = clazz.getComponentType();
            JSONArray jsonArray = new JSONArray();
            for (Map.Entry<String, String[]> entry : map.entrySet()) {
                String key = entry.getKey();
                String[] keys = key.split("\\.");
                if (Objects.equals(name, keys[0])) {
                    String[] values = entry.getValue();
                    for (String value : values) {
                        Map<String, Object> paramMap = new HashMap();
                        paramMap.put(keys[1], value);
                        jsonArray.add(paramMap);
                    }
                }
            }
            return JSON.parseArray(jsonArray.toJSONString(), genericType.getClass());
        }
        Map<String, Object> paramMap = new HashMap();
        for (Map.Entry<String, String[]> entry : map.entrySet()) {
            String key = entry.getKey();
            String[] keys = key.split("\\.");
            if (Objects.equals(name, keys[0])) {
                paramMap.put(keys[1], entry.getValue());
            }
        }
        return JSON.parseObject(JSONObject.toJSONString(paramMap), clazz);
    }

}
